/*************************************************************************
	> File Name: chatserver.cpp
	> Author: 
	> Mail: 
	> Created Time: 二  6/14 14:31:56 2016
 ************************************************************************/

#include <iostream>
#include "chatserver.h"

ChatServer::ChatServer() {
    epoll_fd_ = INVALID_FD;
    server_socket_ = INVALID_FD;
    server_port_ = LISTEN_PORT;
    
}

ChatServer::~ChatServer() {
    close(server_socket_);
    close(epoll_fd_);

    for (auto iter = client_ip2socket_.begin(); iter != client_ip2socket_.end(); ++iter) {
        close(iter->second);
    }
}

int ChatServer::addIPtoMulti(std::string ip, std::string source_ip) {
    multiaddr2ips_[ip].push_back(source_ip);
    return 0;
}

int ChatServer::delIPfromMulti(std::string ip, std::string source_ip) {
    multiaddr2ips_.erase(ip);
    return 0;
}

int ChatServer::sendMsgtoMulti(std::string multi_ip_addr, std::string source_ip, std::string msg) {
    std::vector<std::string> dest_ips = multiaddr2ips_[multi_ip_addr];
    std::string dest_ip;
    int dest_socket;
    Json::Value dest_msg_json;
    std::string dest_msg;
    Json::FastWriter wr;

    for (auto iter = dest_ips.begin(); iter != dest_ips.end(); ++iter) {
        if (*iter == source_ip) {
            continue;
        }
        dest_msg_json["type"] = "r04";
        dest_msg_json["ip"] = source_ip;
        dest_socket = client_ip2socket_[*iter];
        dest_msg_json["msg"] = msg.c_str();
        dest_msg_json["multi_ip_addr"] = multi_ip_addr;
        dest_msg = wr.write(dest_msg_json);
        write(dest_socket, dest_msg.c_str(), strlen(dest_msg.c_str()) + 1);
        std::cout << "multi " << dest_msg << std::endl;
    }
}

int ChatServer::initSocket() {
    if ((epoll_fd_ = epoll_create(MAX_LISTEN_FD_NUM)) == -1) {
        std::cout << "epoll_create failed......" << std::endl; 
        return -1;
    }
    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_port = htons(server_port_);

    if ((server_socket_ = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        return -1;
    }

    if (setSocket(server_socket_, O_NONBLOCK) == -1) {
        std::cout << "setSocket failed......" << std::endl;
        return -1;
    }

    if (bind(server_socket_, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
        return -1;
    }

    if (listen(server_socket_, MAX_LISTEN_FD_NUM) == -1) {
        return -1;
    }

    return 0;
}

int ChatServer::setSocket(int fd, int flag) {
    int option_value = 1;
    int ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &option_value, sizeof(option_value));
    if (ret < 0) {
        return -1;
    }
    option_value = fcntl(fd, F_GETFL);
    ret = fcntl(fd, F_SETFL, option_value | flag);
    if (ret < 0) {
        return -1;
    }
    return 0;
}

int ChatServer::addFd(int fd, int flag) {
    epoll_event event;
    event.events = flag;
    event.data.fd = fd;
    epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, fd, &event);
    return 0;
}

int ChatServer::deleteFd(int fd, int flag) {
    epoll_event event;
    event.events = flag;
    event.data.fd = fd;
    epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, fd, &event);

    return 0;
}

int ChatServer::run() {
   
    if (initSocket() == -1) {
        std::cout << "initSocket failed......" << std::endl;
        return -1;
    }
    addFd(server_socket_, EPOLLIN);
    while (true) {
        int epoll_ready_num = epoll_wait(epoll_fd_, epoll_ready_event_, MAX_EPOLL_EVENT_NUM, -1);
        if (epoll_ready_num == -1) {
            std::cout << "epoll_wait failed......" << std::endl;
            return -1;
        }

        for (int num = 0; num < epoll_ready_num; ++num) {
            int ready_fd = epoll_ready_event_[num].data.fd;
            if (ready_fd == server_socket_) {
                struct sockaddr_in client_addr;
                int client_addr_len = sizeof(client_addr);
                int conn_fd = accept(server_socket_, (struct sockaddr *)&client_addr, (socklen_t *)&client_addr_len);
                addFd(conn_fd, EPOLLIN);
                char client_ip[16];
                inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, sizeof(client_ip));
                int client_port = ntohs(client_addr.sin_port);
                std::string str_client_ip(client_ip);

                client_ip2socket_[str_client_ip] = conn_fd;
                socket2client_ip_[conn_fd] = str_client_ip;

                std::cout << "client_ip : " << str_client_ip << "  port : " << client_port << std::endl;
            }
            else {
                int read_bytes = read(ready_fd, read_buf_, MAX_RECV_BUF);
                //client disconnect
                std::cout << "recv msg:" << read_buf_ << std::endl;
                std::string source_ip = socket2client_ip_[ready_fd];
                if (read_bytes == 0) {
                    client_ip2socket_.erase(client_ip2socket_.find(source_ip));
                    socket2client_ip_.erase(socket2client_ip_.find(ready_fd));
                    deleteFd(ready_fd, EPOLLIN);
                    continue;
                }
                std::string message(read_buf_);
                Json::Reader reader;
                Json::Value j_val;
                Json::FastWriter wr;
                std::string dest_ip;
                std::string type;
                Json::Value reply_json;
                std::string reply_msg;

                if (!reader.parse(message, j_val)) {
                    std::cout << "reader.parse failed......" << std::endl;
                    continue;
                }
                if (j_val.isMember("type") && j_val["type"].isString()) {
                    type = j_val["type"].asString();
                }
                //type为m01，代表消息同步
                if (type == "m01") {
                    std::string client_ip = socket2client_ip_[ready_fd];
                    auto tmp_iter = dest_ip2message_.find(client_ip);
                    reply_json["type"] = "r01";
                    Json::Value reply_array_msg = Json::arrayValue;
                    if (tmp_iter == dest_ip2message_.end()) {
                        reply_json["msg"] = reply_array_msg;
                        reply_msg = wr.write(reply_json);
                        write(ready_fd, reply_msg.c_str(), strlen(reply_msg.c_str()) + 1);
                        std::cout << client_ip << " 同步无消息" << std::endl;
                    }
                    else {
                        std::vector<std::string> msg_vec = dest_ip2message_[client_ip];
                        std::string sync_msg;
                        const char *msg;
                        int offset = 0;
                        Json::Value tmp_json_value;

                        for (auto iter = msg_vec.begin(); iter != msg_vec.end(); ++iter) {
                            reader.parse(*iter, tmp_json_value);
                            reply_array_msg.append(tmp_json_value);
                        }
                        reply_json["msg"] = reply_array_msg;
                        reply_msg = wr.write(reply_json);
                        write(ready_fd, reply_msg.c_str(), strlen(reply_msg.c_str()) + 1);
                        dest_ip2message_.erase(tmp_iter);
                        std::cout << "要同步的消息为 " << reply_msg << std::endl;
                    }
                 //   continue;
                }
                //type为m00，代表正常消息
                else if (type == "m00") {
                    std::cout << "m00:" << message << std::endl;
                    dest_ip = j_val["ip"].asString();
                    j_val["type"] = "r00";
                    j_val["ip"] = source_ip;
                    message = wr.write(j_val);
                    int dest_socket;
                    auto key_iter = client_ip2socket_.find(dest_ip);
                    if (key_iter == client_ip2socket_.end()) {
                        reply_json["type"] = "r02";
                        reply_json["ip"] = dest_ip;
                        reply_json["msg"] = "你的好友不在线，可能无法及时回复你的消息";
                        reply_msg = wr.write(reply_json);
                        write(ready_fd, reply_msg.c_str(), strlen(reply_msg.c_str()) + 1);
                    
                        dest_ip2message_[dest_ip].push_back(message); 
                    }
                    else {
                        dest_socket = key_iter->second;
                        int write_bytes = write(dest_socket, message.c_str(), strlen(message.c_str()) + 1);
                    }
                }
                //type为m02，代表加入指定多播组
                else if (type == "m02") {
                    std::string multi_ip_addr = j_val["multi_ip_addr"].asString();
                    addIPtoMulti(multi_ip_addr, source_ip);
                }
                //type为m03，代表离开指定多播组
                else if (type == "m03") {
                    std::string multi_ip_addr = j_val["multi_ip_addr"].asString();
                    delIPfromMulti(multi_ip_addr, source_ip);
                }
                //type为m04，代表向指定多播组发送消息
                else if (type == "m04") {
                    std::string multi_ip_addr = j_val["multi_ip_addr"].asString();
                    std::string multi_msg = j_val["msg"].asString();
                    sendMsgtoMulti(multi_ip_addr, source_ip, multi_msg);
                }
            }
        }
    }
}
